----系统场和练习场模式游戏流程逻辑
local skynet = require "skynet"
local base = require "base"
local timetool = require "timetool"
local tabletool = require "tabletool"
local timer = require "timer"
local filename = "sygamelogic.lua"
local filelog = require "filelog"
local dncardtool = require "dncardtool"
local handcardstool = require "handcardstool"
require "pubenum"
require "ernnenum"

local sygamelogic = {
    server = nil,
    state_protect = false,
}

function sygamelogic.init(service)
    if sygamelogic.server == nil then
        sygamelogic.server = service
    end
end

function sygamelogic.initstate(gameobj, tableobj)
    gameobj.tableobj = tableobj
    gameobj.stateevent[DNTableState.DN_TABLE_STATE_GAME_START] = sygamelogic.game_start
    gameobj.stateevent[DNTableState.DN_TABLE_STATE_ONE_GAME_START] = sygamelogic.one_game_start
    gameobj.stateevent[DNTableState.DN_TABLE_STATE_DEAL_FOUR_CARDS] = sygamelogic.deal_four_cards
    gameobj.stateevent[DNTableState.DN_TABLE_STATE_DEAL_FIVE_CARDS] = sygamelogic.deal_five_cards
    gameobj.stateevent[DNTableState.DN_TABLE_STATE_DEAL_LAST_CARDS] = sygamelogic.deal_last_cards
    gameobj.stateevent[DNTableState.DN_TABLE_STATE_QIANG_ZHUANG] = sygamelogic.qiang_zhuang
    gameobj.stateevent[DNTableState.DN_TABLE_STATE_XIAZHU] = sygamelogic.xiazhu
    gameobj.stateevent[DNTableState.DN_TABLE_STATE_KAIPAI] = sygamelogic.kaipai
    gameobj.stateevent[DNTableState.DN_TABLE_STATE_ONE_GAME_END] = sygamelogic.one_game_end
    gameobj.stateevent[DNTableState.DN_TABLE_STATE_ONE_GAME_END_AFTER] = sygamelogic.one_game_end_after
end

function sygamelogic.run(gameobj)
    local f = nil
    local loopcount = 1
    while true do
        if gameobj.tableobj.state == DNTableState.DN_TABLE_STATE_WAIT_ALL_READY then
            break
        end
        f = gameobj.stateevent[gameobj.tableobj.state]
        if f == nil then
            break
        end
        if loopcount <= 0 then
            ---filelog.sys_error("----------sygamelogic out of looptimes--------", loopcount, "----table.state----", gameobj.tableobj.state)
            break
        end
        if sygamelogic.state_protect == false then
            f(gameobj)
        elseif sygamelogic.state_protect == true then
            filelog.sys_error("-----sygamelogic---在状态切换执行函数执行时，又执行了一次状态切换函数，状态机的状态是：", gameobj.tableobj.state, debug.traceback())
        end
        loopcount = loopcount - 1
    end
end

local function get_curr_round_code(value)
    local code = ""
    if value >= 0 and value < 10 then
        code = code .. "000" ..tostring(value)
    elseif value >= 10 and value < 100 then
        code = code .. "00" .. tostring(value)
    elseif value >= 100 and value <1000 then
        code = code .. "0" .. tostring(value)
    else
        code = code .. tostring(value)
    end
    return code
end


function sygamelogic.onegamestart_inittable(gameobj)
	local tableobj = gameobj.tableobj
    local server = sygamelogic.server
    local tablelogic = server:get_logicbyname("tablelogic")
    ----从配置中获取服务费率
    tablelogic.set_tip()
	tableobj.one_start_time = timetool.get_time()
    tableobj.one_end_time = 0
	tableobj.banker_seat_index = 0     --当前庄家位置
    tableobj.conf.curr_round_code = get_curr_round_code(tableobj.one_start_time % 10000)
    if handcardstool.isopen == true then
        if tableobj.cardspools == nil then
            tableobj.cardspools = {}
            local temp = tabletool.deepcopy(handcardstool.cardspool)
            for i = 1, #temp do
                table.insert(tableobj.cardspools, table.remove(temp, base.get_random(1, #temp)))
            end
        end
    end
	if tableobj.timer_id > 0 then
		timer.cleartimer(tableobj.timer_id)
		tableobj.timer_id = -1
	end
    if tableobj.tablerecords == nil then
        tableobj.tablerecords = {}
    end
    if tableobj.tablerecords.actions == nil then
        tableobj.tablerecords.actions = {}
    end
end

function sygamelogic.send_gamestart_notice(gameobj)
    local server = sygamelogic.server
	local tableobj = gameobj.tableobj
    local roomtablelogic = server:get_logicbyname("tablelogic")
	local noticemsg = {
		game_info = {
            table_baseinfo = {},
		    table_conf = {},
		    seat_baseinfo = {},
		    seat_playerinfo = {}, 
        }
	}
	roomtablelogic.copy_table_game_info(noticemsg.game_info)
    local allrids = roomtablelogic.getallrids(tableobj)
    server:send_notice_to_players(allrids, "gamestartN", noticemsg, nil, nil)
end

function sygamelogic.game_start(gameobj)
    sygamelogic.state_protect = true
    local tableobj = gameobj.tableobj
    tableobj.state = DNTableState.DN_TABLE_STATE_WAIT_PLAYER_SITDOWN
    if tableobj.timer_id > 0 then
        timer.cleartimer(tableobj.timer_id)
        tableobj.timer_id = -1
    end
    local noticemsg = {
        table_index = tableobj.conf.table_index,
        neednum = tableobj.conf.max_player_num - 1,
    }
    tableobj.timer_id = timer.settimer(0.1*100, "train_add_mirror", noticemsg)
    sygamelogic.state_protect = false
end

function sygamelogic.one_game_start(gameobj)
    --filelog.sys_error("-----sygamelogic.one_game_start------")
    sygamelogic.state_protect = true
    local server = sygamelogic.server
    local tableobj = gameobj.tableobj
    local tablelogic = server:get_logicbyname("tablelogic")
    sygamelogic.onegamestart_inittable(gameobj)
    ----清除旁观列表里的玩家
    tablelogic.kill_all_waiter()
	tableobj.curr_to_num = tableobj.curr_to_num + 1
	--初始化桌位
	local seatlogic = server:get_logicbyname("seatlogic")
	for  _, seat in pairs(tableobj.seats) do
		if not seatlogic.is_empty(seat) and seat.state ~= DNSeatState.SEAT_STATE_WAIT_NEXT_GAME then
			seatlogic.onegamestart_initseat(seat)
            seat.state = DNSeatState.SEAT_STATE_PLAYING
		end
	end
	--初始化牌堆
	tableobj.cards_stack = dncardtool.get_new_cards()
	--通知client游戏开始
	sygamelogic.send_gamestart_notice(gameobj)
	tableobj.state = DNTableState.DN_TABLE_STATE_ONE_WAIT_GAME_START
    local noticemsg = {
        table_index = tableobj.conf.table_index,
    }
	local timer_id = timer.settimer(140, "one_game_start", noticemsg)	
	if tableobj.state ~= DNTableState.DN_TABLE_STATE_ONE_WAIT_GAME_START then
		timer.cleartimer(timer_id)
        tableobj.timer_id = -1
	else
		tableobj.timer_id = timer_id
	end
    sygamelogic.state_protect = false
end

function sygamelogic.qiang_zhuang(gameobj)
    sygamelogic.state_protect = true
    local server = sygamelogic.server
    local tableobj = gameobj.tableobj
    --filelog.sys_error("-------sygamelogic.qiang_zhuang-----------")
    local action_time = 0
    if tableobj.conf.play_game_type == DNQZType.QZ_TYPE_FREE then
        action_time = DNActionTime.ZIYOU_QIANGZHUANG
    elseif tableobj.conf.play_game_type == DNQZType.QZ_TYPE_KANPAI then
        action_time = DNActionTime.KANPAI_QIANGZHUANG
    end
    local tablelogic = server:get_logicbyname("tablelogic")
    local rids = tablelogic.getallrids(tableobj)
    for index, seat in ipairs(tableobj.seats) do
        ----通知座位上的每个玩家抢庄
        --[[
            //通知玩家操作
        message todoN {
	        optional int32 rid = 1;
	        optional int32 seat_index = 2;
	        optional int32 action_to_time = 3;  //玩家操作到期时间
            optional int32 action_type = 4;
	        repeated int32 choice_times = 5;     //可以选择的倍数 
        }
        ]]
        if seat.rid ~= 0 and seat.state ~= DNSeatState.SEAT_STATE_WAIT_NEXT_GAME then
            local noticemsg = {
                rid = seat.rid,
                seat_index = seat.index,
                action_to_time = action_time + timetool.get_time(),
                action_type = DNActionType.ACTION_QIANGZHUANG,
                choice_times = DNQiangzhuangTimes[tableobj.conf.xia_zhu_type],
            }
            local timernoticemsg = {
                table_index = tableobj.conf.table_index,
                seat_index = seat.index,
                rid = seat.rid,
            }
            if tableobj.conf.table_type == DNTableType.TABLE_TYPE_TRAIN then
                if seat.is_mirror == true then
                    seat.timer_id = timer.settimer(base.get_random(2,3)* 100, "qiang_zhuang", timernoticemsg)
                elseif seat.is_mirror == false then
                    seat.timer_id = timer.settimer(action_time * 100, "qiang_zhuang", timernoticemsg)
                end
            else
                seat.timer_id = timer.settimer(action_time * 100, "qiang_zhuang", timernoticemsg)
            end
            seat.action_to_time = action_time + timetool.get_time()
            server:send_notice_to_players(rids, "todoN", noticemsg, nil, nil)
            seat.state = DNSeatState.SEAT_STATE_QIANGZHUANG
        end
    end
    tableobj.state = DNTableState.DN_TABLE_STATE_WAIT_QIANG_ZHUANG
    sygamelogic.state_protect = false
end

function sygamelogic.deal_four_cards(gameobj)
    sygamelogic.state_protect = true
    local server = sygamelogic.server
    local tableobj = gameobj.tableobj
    local roomseatlogic = server:get_logicbyname("seatlogic")
    --filelog.sys_error("-----sygamelogic.deal_four_cards-----")
    for _, seat in ipairs(tableobj.seats) do
        if seat.rid ~= 0 and seat.state ~= DNSeatState.SEAT_STATE_WAIT_NEXT_GAME then
		    for i=1, 4 do
                if handcardstool.isopen == true then
			        table.insert(seat.cards, table.remove(tableobj.cardspools[seat.index], 1))
                else
                    table.insert(seat.cards, table.remove(tableobj.cards_stack, 1))
                end
		    end
        end				
	end

	local noticemsg = {}
	for _, seat in ipairs(tableobj.seats) do
		if roomseatlogic.is_ingame(seat) then
            roomseatlogic.dealcards(seat)
        end		
	end
	--设置发牌结束定时器
	tableobj.state = DNTableState.DN_TABLE_STATE_WAIT_DEAL_FOUR_CARDS_END
    local timernoticemsg = {
        table_index = tableobj.conf.table_index,
    }
	local timer_id = timer.settimer(100, "deal_four_cards_over", timernoticemsg)
	if tableobj.state ~= DNTableState.DN_TABLE_STATE_WAIT_DEAL_FOUR_CARDS_END then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end
    sygamelogic.state_protect = false
end

function sygamelogic.deal_five_cards(gameobj)
    sygamelogic.state_protect = true
    local server = sygamelogic.server
    local tableobj = gameobj.tableobj
    --filelog.sys_error("---------xxxxxxxx------sygamelogic.deal_five_cards--")
    local roomseatlogic = server:get_logicbyname("seatlogic")
    for _, seat in ipairs(tableobj.seats) do
        if roomseatlogic.is_ingame(seat) then
		    for i=1, 5 do
                if handcardstool.isopen == true then
			        table.insert(seat.cards, table.remove(tableobj.cardspools[seat.index], 1))
                else
                    table.insert(seat.cards, table.remove(tableobj.cards_stack, 1))
                end
		    end
        end				
	end
	local noticemsg = {}
	for _, seat in ipairs(tableobj.seats) do
		if roomseatlogic.is_ingame(seat) then
            roomseatlogic.dealcards(seat)
        end		
	end
	--设置发牌结束定时器
	tableobj.state = DNTableState.DN_TABLE_STATE_WAIT_DEAL_FIVE_CARDS_END
    local timernoticemsg = {
        table_index = tableobj.conf.table_index,
    }
	local timer_id = timer.settimer(100, "deal_five_cards_over", timernoticemsg)
	if tableobj.state ~= DNTableState.DN_TABLE_STATE_WAIT_DEAL_FIVE_CARDS_END then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end
    sygamelogic.state_protect = false
end

function sygamelogic.deal_last_cards(gameobj)
    sygamelogic.state_protect = true
    local server = sygamelogic.server
    local tableobj = gameobj.tableobj
    --filelog.sys_error("-----sygamelogic.deal_last_cards---")
    local roomseatlogic = server:get_logicbyname("seatlogic")
    for _, seat in ipairs(tableobj.seats) do
        if roomseatlogic.is_ingame(seat) then
            if #seat.cards < 5 then  
                if handcardstool.isopen == true then
			        table.insert(seat.cards, table.remove(tableobj.cardspools[seat.index], 1))
                else
                    table.insert(seat.cards, table.remove(tableobj.cards_stack, 1))
                end
            end
        end				
	end
	local noticemsg = {}
	for _, seat in ipairs(tableobj.seats) do
		if roomseatlogic.is_ingame(seat) then
            roomseatlogic.dealcards(seat)
        end		
	end
	--设置发牌结束定时器
	tableobj.state = DNTableState.DN_TABLE_STATE_WAIT_DEAL_LAST_CARDS_END
    local timernoticemsg = {
        table_index = tableobj.conf.table_index,
    }
	local timer_id = timer.settimer(25, "deal_last_cards_over", timernoticemsg)
	if tableobj.state ~= DNTableState.DN_TABLE_STATE_WAIT_DEAL_LAST_CARDS_END then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end
    sygamelogic.state_protect = false
end

function sygamelogic.xiazhu(gameobj)
    sygamelogic.state_protect = true
    local server = sygamelogic.server
    local tableobj = gameobj.tableobj
    local roomseatlogic = server:get_logicbyname("seatlogic")
    local tablelogic = server:get_logicbyname("tablelogic")
    local rids = tablelogic.getallrids(tableobj)
    --filelog.sys_error("----sygamelogic.xiazhu---")
    for index, seat in ipairs(tableobj.seats) do
        ----通知座位上的每个玩家抢庄
        --[[
            //通知玩家操作
        message todoN {
	        optional int32 rid = 1;
	        optional int32 seat_index = 2;
	        optional int32 action_to_time = 3;  //玩家操作到期时间
            optional int32 action_type = 4;
	        repeated int32 choice_times = 5;     //可以选择的倍数 
        }
        ]]
        if roomseatlogic.is_ingame(seat) and seat.index ~= tableobj.banker_seat_index then
            local noticemsg = {
                rid = seat.rid,
                seat_index = seat.index,
                action_to_time = DNActionTime.XIAZHU_TIME + timetool.get_time(),
                action_type = DNActionType.ACTION_XIAZHU,
                choice_times = DNXiaZhuTimes[tableobj.conf.xia_zhu_type],
            }
            local timernoticemsg = {
                table_index = tableobj.conf.table_index,
                seat_index = seat.index,
                rid = seat.rid,
            }
            if tableobj.conf.table_type == DNTableType.TABLE_TYPE_TRAIN then
                if seat.is_mirror == true then
                    seat.timer_id = timer.settimer(base.get_random(2,3)* 100, "xia_zhu", timernoticemsg)
                elseif seat.is_mirror == false then
                    seat.timer_id = timer.settimer(DNActionTime.XIAZHU_TIME * 100, "xia_zhu", timernoticemsg)
                end
            else
                seat.timer_id = timer.settimer(DNActionTime.XIAZHU_TIME * 100, "xia_zhu", timernoticemsg)
            end
            seat.action_to_time = DNActionTime.XIAZHU_TIME + timetool.get_time()
            server:send_notice_to_players(rids, "todoN", noticemsg, nil, nil)
            seat.state = DNSeatState.SEAT_STATE_XIAZHU
        end
    end
    tableobj.state = DNTableState.DN_TABLE_STATE_WAIT_XIAZHU
    sygamelogic.state_protect = false
end

function sygamelogic.kaipai(gameobj)
    sygamelogic.state_protect = true
    local server = sygamelogic.server
    local tableobj = gameobj.tableobj

    local action_time = 0
    if tableobj.conf.play_game_type == DNQZType.QZ_TYPE_FREE then
        action_time = DNActionTime.ZIYOU_KAIPAI_TIME
    elseif tableobj.conf.play_game_type == DNQZType.QZ_TYPE_KANPAI then
        action_time = DNActionTime.KANPAI_KAIPAI_TIME
    end
    ---filelog.sys_error("---------sygamelogic.kaipai-------")
    local tablelogic = server:get_logicbyname("tablelogic")
    local rids = tablelogic.getallrids(tableobj)
    local roomseatlogic = server:get_logicbyname("seatlogic")
    for index, seat in ipairs(tableobj.seats) do
        ----通知座位上的每个玩家开牌
        --[[
            //通知玩家操作
        message todoN {
	        optional int32 rid = 1;
	        optional int32 seat_index = 2;
	        optional int32 action_to_time = 3;  //玩家操作到期时间
            optional int32 action_type = 4;
	        repeated int32 choice_times = 5;     //可以选择的倍数 
        }
        ]]
        if roomseatlogic.is_ingame(seat) then
            local noticemsg = {
                rid = seat.rid,
                seat_index = seat.index,
                action_to_time = action_time + timetool.get_time(),
                action_type = DNActionType.ACTION_KAIPAI,
                choice_times = {},
            }
            local timernoticemsg = {
                table_index = tableobj.conf.table_index,
                seat_index = seat.index,
                rid = seat.rid,
            }
            if tableobj.conf.table_type == DNTableType.TABLE_TYPE_TRAIN then
                if seat.is_mirror == true then
                    seat.timer_id = timer.settimer(base.get_random(2,4)* 100, "kaipai", timernoticemsg)
                elseif seat.is_mirror == false then
                    seat.timer_id = timer.settimer(action_time * 100, "kaipai", timernoticemsg)
                end
            else
                seat.timer_id = timer.settimer(action_time * 100, "kaipai", timernoticemsg)
            end
            seat.action_to_time = action_time + timetool.get_time()
            server:send_notice_to_players(rids, "todoN", noticemsg, nil, nil)
            seat.state = DNSeatState.SEAT_STATE_KAIPAI
        end
    end
    tableobj.state = DNTableState.DN_TABLE_STATE_WAIT_KAIPAI
    sygamelogic.state_protect = false
end

function sygamelogic.one_game_end(gameobj)
    sygamelogic.state_protect = true
    local server = sygamelogic.server
    local tableobj = gameobj.tableobj
    tableobj.one_end_time = timetool.get_time()
    local roomtablelogic = server:get_logicbyname("tablelogic")
    roomtablelogic.balance(tableobj)
    ----发送结算结果
    --[[
        //游戏结算
        //一局游戏结束,推送游戏结果给玩家
        message gamebalanceN {
            optional int32 basescores = 1; // 底分
            optional int32 times = 2; // 倍数
	        optional int32 service_costs = 3; 	// 本局消耗
	        optional table_gameinfo game_info = 4;
	        repeated player_gameend player_infos = 5; //座位上每个玩家的结算信息
        }
    ]]
    local balancentc = {
        basescores = tableobj.conf.score_diamond,
        times = tableobj.banker_xiazhu_times,
        service_costs = roomtablelogic.get_tip(),
        game_info = {
            table_baseinfo = {},
		    table_conf = {},
		    seat_baseinfo = {},
		    seat_playerinfo = {},
        },
        player_infos = {},
    }
    roomtablelogic.copy_table_game_info(balancentc.game_info)
    roomtablelogic.copy_gameendinfo(balancentc.player_infos)
    local rids = roomtablelogic.getallrids(tableobj)
    server:send_notice_to_players(rids, "gamebalanceN", balancentc, nil, nil)
    tableobj.state = DNTableState.DN_TABLE_STATE_WAIT_ONE_GAME_END
    local delay_time = roomtablelogic.get_movietime()
    local noticemsg = {
        table_index = tableobj.conf.table_index,
    }
    local timer_id = timer.settimer(delay_time, "wait_game_end_over", noticemsg)
	if tableobj.state ~= DNTableState.DN_TABLE_STATE_WAIT_ONE_GAME_END then
		timer.cleartimer(timer_id)
	else
		tableobj.timer_id = timer_id
	end
    sygamelogic.state_protect = false
end

function sygamelogic.one_game_end_after(gameobj)
    sygamelogic.state_protect = true
    local server = sygamelogic.server
    local tableobj = gameobj.tableobj
    local seatlogic = server:get_logicbyname("seatlogic")
    local tablelogic = server:get_logicbyname("tablelogic")
    tablelogic.check_train_mirror()
    ----清除旁观列表里的玩家
    tablelogic.kill_all_waiter()

    local is_table_end = tableobj.table_end_flag
    ---filelog.sys_error("----is_table_end---", is_table_end)
    if is_table_end == true then
        tablelogic.resetdata()
        tableobj.state = DNTableState.DN_TABLE_STATE_WAIT_PLAYER_SITDOWN
        if tableobj.delete_table_timer_id > 0 then
            timer.cleartimer(tableobj.delete_table_timer_id)
            tableobj.delete_table_timer_id = -1
        end
        if tableobj.delete_table_timer_id == -1 then
			local noticemsg = {
				table_index = tableobj.conf.table_index,
				reason = "tableend",
			}
			tableobj.delete_table_timer_id = timer.settimer(1*100, "delete_table", noticemsg)
		end
        return 
    end 

    tablelogic.resetdata()
    tableobj.state = DNTableState.DN_TABLE_STATE_WAIT_PLAYER_SITDOWN
    local rids = tablelogic.getallrids(tableobj)
    for index, seat in ipairs(tableobj.seats) do
        if seat.rid ~= 0 then
            if not seatlogic.is_empty(seat) then
			    seatlogic.resetstate(seat)
		    end
            local outoftimermsg = {
                table_index = tableobj.conf.table_index,
		        rid = seat.rid,
		        seat_index = seat.index,
	        }
            if seat.is_mirror == false then
	            seat.ready_timer_id = timer.settimer(tableobj.conf.ready_timeout*100, "doready", outoftimermsg)
            elseif seat.is_mirror == true then
                seat.ready_timer_id = timer.settimer(base.get_random(2,3)*100, "mirror_doready", outoftimermsg)
            end
            seat.ready_to_time = timetool.get_time() + tableobj.conf.ready_timeout
	        local doreadyntcmsg = {
		        rid = seat.rid,
		        seat_index = seat.index,
		        ready_to_time = timetool.get_time() + tableobj.conf.ready_timeout,
	        }
	        server:send_notice_to_players(rids, "doreadyN", doreadyntcmsg, nil, nil)
        end
    end
    if tableobj.state == DNTableState.DN_TABLE_STATE_WAIT_PLAYER_SITDOWN then
        tableobj.state = DNTableState.DN_TABLE_STATE_WAIT_ALL_READY
    end
    sygamelogic.state_protect = false
end

return sygamelogic